#####################################################################
# Product:      KnowledgeEngine (Plone Edition)
#
# File:         MultiSelectionEditlet.py
#
# Copyright:    Copyright (c) 2004, Faulkner Technologies
#
# Author:       Brian Oliver
#
# Description:  This file defines the MultiSelectionEditlet class, that is
#               used to generate widgets that permit multiple selections
#               of values from enumerated types
#
# See Also:     PropertyEditlet, PropertyRefleciton, 
#               PropertyDefinition, PropertyAccess 
#####################################################################

#####################################################################
## KnowledgeEngine Library Imports
from Products.KnowledgeEngine.Common import *
from Products.KnowledgeEngine.Core import *
from Products.KnowledgeEngine.Editlet import Editlet
from Products.KnowledgeEngine.PropertyDefinition import *
from Products.KnowledgeEngine.PropertyTypes import *
from Products.KnowledgeEngine.PropertyFormats import *
from Products.KnowledgeEngine.PropertyStructures import *

#####################################################################
## Zope Library Imports
# (none)
 
#####################################################################
## Python Library Imports
import string
import types

#####################################################################
## MultiSelectionEditlet Class Definition
class MultiSelectionEditlet(Editlet):
    """
        An editlet for editing enumerated types
        """
    
    #---------------------------------------------------------------#

    def displayNameFor(self, value, possibleValues):
        """
            Returns the displayName for the specified value
            from the specified possible values.
        """
        
        for (displayName, displayValue) in possibleValues:
            if displayValue == value:
                return displayName
               
        raise "Missing Value Exception", "MultiSelectionEditlet can't locate display name for value %s in %s" % (value, possibleValues)
    
    #---------------------------------------------------------------#
    
    def isEditable(self, propertyDefinition, propertyAccess=None, value=None, isForConstructor=false, REQUEST=None, context=None):
        """
            Returns if the specified propertyDefinition can be
            edited by this editlet
        """

        return propertyDefinition.getStructure() in (ps_LIST, ps_SET) and propertyDefinition.hasEnumeratedValues()
        
    #---------------------------------------------------------------#

    def generateEditorFor(self, propertyDefinition, propertyAccess=None, value=None, isForConstructor=false, REQUEST=None, context=None):
        """
            Returns a HTML editlet for the specified property.
        """

        #get the enumerated values [(DisplayName,Value)] from the property definition class (one must be provided)
        possibleValues = propertyDefinition.getEnumeratedValues(context)
                        
        #ensure that we use a writeable editlet (if possible) if we are dealing with a mandatory property and we don't yet have a value
        if propertyDefinition.isMandatory() and propertyAccess is not None and (not hasattr(propertyAccess, propertyDefinition.getIdentity()) or getattr(propertyAccess, propertyDefinition.getIdentity()) is None):
            
            #we want an editletEVAP with the most permissions (which may not include write access)
            editletEVAP = propertyDefinition.getConstructorEVAP() | propertyDefinition.getPropertyEditorEVAP()
        
        else:
            #determine the type of editlet we need to produce based on editlet value access permission (EVAM)
            editletEVAP = iif(isForConstructor, propertyDefinition.getConstructorEVAP(), propertyDefinition.getPropertyEditorEVAP())
                
        #-----------------
        #no property editor is required
        if editletEVAP == evap_NONE:
            result = ""

        #-----------------
        #a read-only property editor is required
        elif editletEVAP == evap_READONLY:

            #get the value for the property
            if isForConstructor or propertyAccess is None:
                value = propertyDefinition.getDefaultValue()
            else:
                value = propertyAccess.getPropertyValue(propertyDefinition.getIdentity())
            
            #create the editor
            result = ""
            for selection in value:
                if len(result) > 0:
                    result += ", "
                result += self.displayNameFor(selection, possibleValues)
           
            result = "<table border=1><tr><td>%s</td></tr></table>" % (result,)
        
        #-----------------
        #a writeable property editor is required
        else: 
       
            #get the value for the property (if possible)
            if editletEVAP == evap_WRITEONLY:
                value = []
            else:
                if isForConstructor or propertyAccess is None:
                    value = propertyDefinition.getDefaultValue()
                else:
                    #get the value for the property
                    value = propertyAccess.getPropertyValue(propertyDefinition.getIdentity())

            #create the editor
            result = ""
            for (displayName, displayValue) in possibleValues:
                #determine if the item is already selected
                if value is not None and str(displayValue) in value:
                    selected = "checked"
                else:
                    selected = ""
            
                #output a line break between items
                if len(result) > 0:
                    result += "<br>"

                #ensure our value doesn't get weirdly cast into a string!
                if propertyDefinition.getType() == pt_LONG or propertyDefinition.getType() == pt_INTEGER:
                    format = "%d"
                elif propertyDefinition.getType() == pt_FLOAT: 
                    format = "%f"
                else:          
                    format = "%s"

                #output a checkbox
                result += ("<input type='%s' id='kems%s' name='kems%s' value='" + format + "' %s> %s") % (
                    iif(propertyDefinition.getStructure() == ps_LIST, 'radio', 'checkbox'),
                    #iif(propertyDefinition.getStructure() == ps_LIST, 'checkbox', 'radio'),
                    propertyDefinition.getIdentity(),
                    propertyDefinition.getIdentity(),
                    displayValue,
                    selected,
                    displayName
                )
                                    
        return result
        
    #---------------------------------------------------------------#

    def containsPropertyValue(self, propertyDefinition, REQUEST):
        """
            Determines if the provided request contains
            a value for the specified propertyDefinition.
            
            This method is used (and is useful for) determining and
            updating the values of properties from property editors.
            
            All editlet implementations must override this method.            
        """
        
        #multi-selection editlets are always present (as no selection means there are no values)
        return true
        
    #---------------------------------------------------------------#

    def updatePropertyWith(self, propertyDefinition, propertyAccess, REQUEST=None):
        """
            Attempts to update the specified property on the
            object implementing the PropertyAccess interface with the
            specified HTTP REQUEST.
        """
        
        #rebuild the entire list from the selections
        #(remember when checkboxes aren't selected, values aren't submitted)
        key = 'kems%s' % propertyDefinition.getIdentity()

        #has anything been selected?
        if not REQUEST.has_key(key):
            value = []
        else:
            value = REQUEST[key]

            #ensure the value is a list (value will be a string if only one item is selected)
            if not type(value) is types.ListType:
                value = [value]

        # Check we have a value if it isMandatory
        propertyDefinition.verifyMandatoryValue(value)

        #set the value for the property
        propertyAccess.setPropertyValue(propertyDefinition.getIdentity(), value)        

        print "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-"
        print "PropertyDefinition: %s" % propertyDefinition.getIdentity()
        print "Value: %s" % value
        print "PropertyAccess: %s" % propertyAccess
        
    #---------------------------------------------------------------#

#####################################################################
## Class Initialisation

# Register Editlet Information with the Knowledge Engine
registerEditlet("MultiSelectionEditlet", MultiSelectionEditlet())

#####################################################################
